package jch.learn.java.advanced.chapter2_InputAndOutput;

import java.io.IOException;
import java.net.URI;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;

public class TestDirectoryStream {

    public static void main(String[] args) throws IOException {
        Path path = getPath();
        System.out.println("-----");
        noGlob(path);
        System.out.println("-----");
        glob(path);
        System.out.println("-----");
        useWalkFileTree(path);

        useSimpleFileVisitor(path);

        deleteDirectoryAndFile(path);
    }

    // 使用 Files.walkFileTree 方法 删除目录及目录下的文件
    private static void deleteDirectoryAndFile(Path path) {
        System.out.println("删除目录及文件：" + path);
        try {
            Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    // 删除文件
                    Files.delete(file);
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                    if (exc != null) throw exc;
                    // 删除文件夹 目录
                    Files.delete(dir);
                    return FileVisitResult.CONTINUE;
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static Path getPath() throws IOException {
        Path path = Paths.get("testDir");
        if (Files.notExists(path)) {
            Files.createDirectory(path);
        }
        createDir(path.toUri());
        for (int i = 0; i < 10; i++) {
            String s = i % 2 == 0 ? "" : ".txt";
            if (Files.notExists(Paths.get("testDir/file" + i + s))) {
                Files.createFile(Paths.get("testDir/file" + i + s));
            }
        }
        return path;
    }

    private static void createDir(URI toUri) throws IOException {
        for (int i = 0; i < 5; i++) {
            if (i % 2 == 0) {
                if (Files.notExists(Paths.get(toUri.getPath().substring(1) + "file" + i))) {
                    System.out.println(Paths.get(toUri.getPath().substring(1) + "file" + i));
                    Files.createDirectory(Paths.get(toUri.getPath().substring(1) + "file" + i));

                    Files.createFile(Paths.get(toUri.getPath().substring(1) + "file" + i + "/test"));
                }
            } else {
                if (Files.notExists(Paths.get(toUri.getPath().substring(1) + "file" + i))) {
                    Files.createFile(Paths.get(toUri.getPath().substring(1) + "file" + i));
                }
            }
        }
    }

    // 使用 Files.newDirectoryStream(path) 遍历目录
    private static void noGlob(Path path) throws IOException {
        try (DirectoryStream<Path> entries = Files.newDirectoryStream(path)) {
            for (Path entry : entries) {
                System.out.println(entry);
            }
        }
    }

    // 使用 Files.newDirectoryStream(path, "*.txt") 遍历目录
    private static void glob(Path path) {
        try (DirectoryStream<Path> entries = Files.newDirectoryStream(path, "*.txt")) {
            for (Path entry : entries) {
                System.out.println(entry);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 访问目录所有子孙成员
    private static void useWalkFileTree(Path path) {
        try {
            Files.walkFileTree(path, new FileVisitor<Path>() {

                // 一个目录被处理前
                @Override
                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                    System.out.println("被处理目录或文件：" + dir + " 之前。");
                    return FileVisitResult.CONTINUE;// 继续访问下一个文件。
                }

                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    System.out.println("处理目录或文件：" + file);
                    return FileVisitResult.CONTINUE;// 继续访问下一个文件。
                }

                @Override
                public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                    System.out.println("处理目录或文件：" + file + " 时，发生错误。");
                    return FileVisitResult.SKIP_SUBTREE; // 继续访问，但不再访问该目录下的任何项了。
                    // FileVisitResult.SKIP_SIBLINGS 继续访问，但不再访问该目录下的兄弟文件了(和该文件在同一个目录下的文件)
                }

                // 在访问目录中的条目及其所有子体后，为目录调用。
                // 当目录的迭代提前完成时（通过返回SKIP_同级的visitFile方法，或在目录上迭代时出现I/O错误），也会调用此方法
                @Override
                public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                    if (exc != null) throw exc;
                    // 删除该目录
                    //Files.delete(dir);
                    return FileVisitResult.CONTINUE;
                    // FileVisitResult.TERMINATE 终止访问
                }
                // 当有任何方法抛出异常时，就会终止访问，该异常会从walkFileTree方法中抛出。
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 使用SimpleFileVisitor展示目录
    private static void useSimpleFileVisitor(Path path) throws IOException {
        System.out.println("展示目录：" + path + " -------");
        Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                System.out.println(dir);
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                System.out.println(file);
                return super.visitFile(file, attrs);
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                return FileVisitResult.SKIP_SUBTREE;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                return FileVisitResult.CONTINUE;
            }
        });
    }
}
